#ifndef _CGCM_PREPROCESSOR_
#define _CGCM_PREPROCESSOR_

#include "forward_classes.h"
#include <string>
#include <vector>
#include <map>
#include <stack>
#include <mpParser.h>

using namespace std;
// --> forward stuff local
class preprocessordata;
struct token;
//***************************************************************************************************/
struct namelistdata {
  string filename;
  string filecontent;
  vector< token > tokens;
  namelistdata();
  bool open(const char * path); 
}; 
//***************************************************************************************************/
struct token {
  enum ttype { NONE,  WORD, SINGLE, MULTI, STRING } type;
  token();
  token( const string &, const int ln, ttype, int);
  string word;
  int line_number;
  int namelist_number;
  // some useful operators that allow tokens to be treated like strings
  int size() const {
    return this->word.size();
  }
  const string & getword() const {
    return this->word;
  }
  const char * c_str() const {
    return this->word.c_str();
  }
};

//***************************************************************************************************/
class preprocessor { // collection of static functions that actually does the preprocessing
  public:
    class local; // collection of static functions that do not need declarations or definitions in 
    // this header file.
    static void combinetokens(const vector<token> &, mup::token_list &);
    static void combinetokens(const vector<token> &, mup::token_list &, int spos, int epos);

    // split strings into preprocesing tokens for processing and save data in namelist
    static void tokenizestring(const string &, vector<token> &); // split string into string tokens for processing 

    static bool invoke(preprocessordata &, const char *);

    static void get_preproc_arg(model_class & mo, mup::token_list & output, const vector<token> &, int & pos, bool);

};
//***************************************************************************************************/
class preprocessordata {
  friend class preprocessor;
  friend class model_class;
  friend class compiler; 
  friend class debugger; 
  model_class * mo;
  vector<namelistdata*> namelists; // mantain as a list of pointers!
  vector<token> processed_namelist; // aggregate of all the preprocessed namelist files
  stack<int> current_namelist_index; 

  map< string, mup::token_list > macrolist;

  explicit preprocessordata(); // no implicit calls
  explicit preprocessordata(const preprocessordata &); // no implicit copy constructor
  preprocessordata & operator=(const preprocessordata &); // no assignments allowed

  public:

  preprocessordata(model_class *); // default constructor
  const vector<token> & get_processed_namelist() const;
  void readnamelist(const char * namelist); // adds data

#ifdef DEBUG
  void dump() const;
  void dumptokens() const;
#endif

  const map< string, mup::token_list > & getmacrolist() const;
  const mup::token_list & getmacrobyname(const string &) const;
  bool addmacrolist(const string &);
  bool definemacro(const string &, const mup::token_list &);
  bool definemacro(const string &, const string &);
  bool undefinemacro(const string &);
  bool doesmacroexist(const string &) const;
  void clearmacrolist();

  const namelistdata & getnamelistbyid(int) const;

};
//***************************************************************************************************/
// Global functions

bool extract_words(const string &, mup::token_list &);
#endif
